package com.ibeeking.gmc.global.g.rest.service.impl;

import cn.hutool.db.meta.TableType;
import com.ibeeking.found.common.constants.*;
import com.ibeeking.found.common.entity.TenantExtendInfo;
import com.ibeeking.gmc.global.g.rest.config.prop.FileConfigProp;
import com.ibeeking.gmc.global.g.rest.service.*;
import com.ibeeking.found.common.config.prop.FileOssProp;
import com.ibeeking.found.common.entity.DictDTO;
import com.ibeeking.found.common.entity.OperatorDTO;
import com.ibeeking.found.common.entity.TimeTaskJobParam;
import com.ibeeking.found.common.enums.*;
import com.ibeeking.found.common.utils.DateUtils;
import com.ibeeking.found.common.utils.EmailCheckUtils;
import com.ibeeking.found.common.utils.MobileCheckUtils;
import com.ibeeking.found.common.utils.UrlUtils;
import com.ibeeking.gmc.global.api.common.dto.TenantDTO;
import com.ibeeking.gmc.global.api.common.dto.TenantListDTO;
import com.ibeeking.gmc.global.api.common.dto.TenantUserDTO;
import com.ibeeking.gmc.global.api.common.param.PermissionParam;
import com.ibeeking.gmc.global.api.feign.UpmsTenantUserClient;
import com.ibeeking.gmc.global.service.common.bo.DatasourceConfigBO;
import com.ibeeking.gmc.global.service.common.bo.DatabaseTemplateBO;
import com.ibeeking.gmc.global.service.common.constants.RedisKeyConstant;
import com.ibeeking.gmc.global.service.common.constants.enums.TenantInitEnum;
import com.ibeeking.gmc.global.service.common.dos.GroupDO;
import com.ibeeking.gmc.global.service.common.dos.TenantDO;
import com.ibeeking.gmc.global.service.common.dos.TenantDatasourceDO;
import com.ibeeking.gmc.global.service.common.param.TenantParam;
import com.ibeeking.gmc.global.service.common.param.TenantPermissionItem;
import com.ibeeking.gmc.global.service.common.param.TenantPermissionParam;
import com.ibeeking.gmc.global.service.common.po.TenantUserPO;
import com.ibeeking.gmc.global.service.common.query.TenantEffectiveQuery;
import com.ibeeking.gmc.global.service.common.query.TenantPageQuery;
import com.ibeeking.gmc.global.service.common.query.TenantQuery;
import com.ibeeking.gmc.global.service.common.vo.TenantEffectiveVO;
import com.ibeeking.gmc.global.service.common.vo.TenantVO;
import com.ibeeking.gmc.global.service.common.vo.TenantViewVO;
import com.ibeeking.gmc.global.service.common.vo.TimeTaskVO;
import com.ibeeking.gmc.global.service.mapper.TenantDatasourceMapper;
import com.ibeeking.gmc.global.service.mapper.TenantMapper;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.nematos.constants.enums.LogClassifyEnum;
import com.ibeeking.nematos.constants.enums.LogConstant;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.redis.annotation.CacheQuery;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.date.DateUtil;
import com.ibeeking.nematos.utils.file.FileUtils;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseCodeEnum;
import com.ibeeking.nematos.utils.result.ResponseResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.ClassUtils;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName TenantServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2020-12-24 09:21
 **/
@Service
public class TenantServiceImpl extends ServiceImpl<TenantMapper, TenantDO> implements ITenantService {

    private static final String INIT_TENANT_LOCK = "INIT_TENANT_LOCK:";

    private static final String INIT_PROCESS_LOG = "tenent_init_process.log";

    @Resource
    private TenantMapper tenantMapper;
    @Resource
    private TenantDatasourceMapper tenantDatasourceMapper;
    @Resource
    private ITimeTaskService timeTaskServiceImpl;
    @Resource
    private ITenantEnterpriseInfoService tenantEnterpriseInfoService;
    @Resource
    private ITenantBankService tenantBankService;
    @Resource
    private ITenantLegalInfoService tenantLegalInfoService;
    @Resource
    private ITenantDetailService tenantDetailService;
    @Resource
    private IDictValueService dictValueService;
    @Resource
    private IGroupService groupService;
    @Resource
    private FileOssProp fileOssProp;
    @Resource
    private FileConfigProp fileConfigProp;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private IDatasourceConfigService templateDatabaseConfigServiceImpl;
    @Resource
    private IDatabaseTemplateService templateDatabaseServiceImpl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private UpmsTenantUserClient upmsTenantUserClient;
    @Resource
    private IJobCreateService jobCreateServiceImpl;

    @Override
    public Page<TenantVO> pageList(TenantPageQuery tenantPageQuery) {
        QueryWrapper<TenantDO> queryWrapper = new QueryWrapper<>();
        //根据创建时间倒序
        queryWrapper.lambda().orderByAsc(TenantDO::getCreateTime);
        //租户名称模糊查询
        queryWrapper.lambda().like(StringUtils.isNotBlank(tenantPageQuery.getName()), TenantDO::getName, tenantPageQuery.getName());
        //租户联系人模糊查询
        queryWrapper.lambda().like(StringUtils.isNotBlank(tenantPageQuery.getContacts()), TenantDO::getName, tenantPageQuery.getContacts());
        //经营泪目
        queryWrapper.lambda().eq(tenantPageQuery.getBusinessCategory() != null, TenantDO::getBusinessCategory, tenantPageQuery.getBusinessCategory());
        //账号期限 开始
        if (StringUtils.isNotBlank(tenantPageQuery.getAccountBegin())) {
            LocalDate accountBegin = DateUtil.strToLocalDate(tenantPageQuery.getAccountBegin());
            queryWrapper.lambda().eq(TenantDO::getAccountBegin, accountBegin);
        }
        //账号期限 结束
        if (StringUtils.isNotBlank(tenantPageQuery.getAccountEnd())) {
            LocalDate accountEnd = DateUtil.strToLocalDate(tenantPageQuery.getAccountEnd());
            queryWrapper.lambda().eq(TenantDO::getAccountEnd, accountEnd);
        }
        queryWrapper.lambda().eq(tenantPageQuery.getStatus() != null, TenantDO::getPublishStatus, tenantPageQuery.getStatus());
        Page<TenantDO> pages = tenantMapper.selectPage(new Page<>(tenantPageQuery.getPageNum(), tenantPageQuery.getPageSize()), queryWrapper);
        Page<TenantVO> result = BeanUtil.convertPage(pages, TenantVO.class);
        Map<Integer, String> tenantTypeMap = dictValueService.queryDictByType(DictTypeEnum.TENANT_TYPE.getValue())
                .stream().collect(Collectors.toMap(dictDTO -> Integer.valueOf(dictDTO.getValue()), DictDTO::getLabel, (s, a) -> a));

        Map<Integer, String> tenantBusinessCategoryMap = dictValueService.queryDictByType(DictTypeEnum.TENANT_BUSINESS_CATEGORY.getValue())
                .stream().collect(Collectors.toMap(dictDTO -> Integer.valueOf(dictDTO.getValue()), DictDTO::getLabel, (s, a) -> a));
        Optional.ofNullable(result.getRecords()).ifPresent(lis -> lis.stream().forEach(tenantVO -> {
            tenantVO.setTenantTypeName(tenantTypeMap.get(tenantVO.getTenantType()));
            tenantVO.setIndustryName(IndustryTypeEnum.getNameByCode(tenantVO.getIndustry()));
            tenantVO.setBusinessCategoryName(tenantBusinessCategoryMap.get(tenantVO.getBusinessCategory()));
            tenantVO.setLogoFullPath(UrlUtils.addUrlDomainName(fileOssProp.getHost(),tenantVO.getLogo()));
            if(StringUtils.isNotEmpty(tenantVO.getExtendInfoJson())){
                TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantVO.getExtendInfoJson(), TenantExtendInfo.class);
                tenantVO.setExtendInfo(extendInfo);
            }
        }));

        return result;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(TenantParam tenantParam) {
        checkTenant(tenantParam);
        TenantDO tenantDO = BeanUtil.convertBean(tenantParam, TenantDO.class);
        tenantDO.setModifyBy(tenantParam.getModifyBy()).setCreateBy(tenantParam.getCreateBy());
        tenantDO.setCreateTime(LocalDateTime.now()).setModifyTime(LocalDateTime.now());
        tenantDO.setPublishStatus(PublishStatusEnum.DISABLE.getValue());
        tenantDO.setAccountBegin(DateUtil.strToLocalDate(tenantParam.getAccountBegin()));
        tenantDO.setAccountEnd(DateUtil.strToLocalDate(tenantParam.getAccountEnd()));
        if (tenantDO.getAccountEnd().isBefore(tenantDO.getAccountBegin())) {
            throw new BusinessException("账号期限结束时间不能小于开始时间");
        }
        tenantDO.setLogo(DefaultPathConstant.DEFAULT_TENANT_LOGO_IMAGE);
        if(tenantParam.getExtendInfo() != null){
            String extendInfoStr = JsonUtils.toJsonStr(tenantParam.getExtendInfo());
            tenantDO.setExtendInfoJson(extendInfoStr);
        }
        return tenantMapper.insert(tenantDO) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean modify(TenantParam tenantParam) {
        checkTenant(tenantParam);
        TenantDO tenantDO = BeanUtil.convertBean(tenantParam, TenantDO.class);
        tenantDO.setModifyBy(tenantParam.getModifyBy()).setCreateBy(tenantParam.getCreateBy());
        tenantDO.setModifyTime(LocalDateTime.now());
        tenantDO.setAccountBegin(DateUtil.strToLocalDate(tenantParam.getAccountBegin()));
        tenantDO.setAccountEnd(DateUtil.strToLocalDate(tenantParam.getAccountEnd()));
        if (tenantDO.getAccountEnd().isBefore(tenantDO.getAccountBegin())) {
            throw new BusinessException("账号期限结束时间不能小于开始时间");
        }
        if(tenantParam.getExtendInfo() != null){
            String extendInfoStr = JsonUtils.toJsonStr(tenantParam.getExtendInfo());
            tenantDO.setExtendInfoJson(extendInfoStr);
        }
        return tenantMapper.updateById(tenantDO) > 0;
    }

    @Override
    public TenantVO view(Integer id) {
        TenantDO tenantDO = tenantMapper.selectById(id);
        TenantVO tenantVO = BeanUtil.convertBean(tenantDO, TenantVO.class);
        tenantVO.setAccountBegin(DateUtil.parseStr(tenantDO.getAccountBegin()))
                .setAccountEnd(DateUtil.parseStr(tenantDO.getAccountEnd()));
        tenantVO.setLogoFullPath(UrlUtils.addUrlDomainName(fileOssProp.getHost(),tenantVO.getLogo()));
        if(StringUtils.isNotEmpty(tenantDO.getExtendInfoJson())){
            TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantVO.getExtendInfoJson(), TenantExtendInfo.class);
            tenantVO.setExtendInfo(extendInfo);
        }
        return tenantVO;
    }

    @Override
    public TenantViewVO viewCertInfo(Integer tenantid) {
        TenantViewVO viewVO = new TenantViewVO();
        TenantDO tenantDO = tenantMapper.selectById(tenantid);
        TenantVO tenantVO = BeanUtil.convertBean(tenantDO, TenantVO.class);
        tenantVO.setAccountBegin(DateUtil.parseStr(tenantDO.getAccountBegin()))
                .setAccountEnd(DateUtil.parseStr(tenantDO.getAccountEnd()))
                .setLogoFullPath(UrlUtils.addUrlDomainName(fileOssProp.getHost(),tenantVO.getLogo()));
        viewVO.setTenantParam(tenantVO)
                .setEnterpriseInfoParam(this.tenantEnterpriseInfoService.viewByTenantId(tenantid))
                .setLegalInfoParam(this.tenantLegalInfoService.viewByTenantId(tenantid))
                .setTenantBankParam(this.tenantBankService.queryByTenantId(tenantid.intValue()));
        if(StringUtils.isNotEmpty(tenantDO.getExtendInfoJson())){
            TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantVO.getExtendInfoJson(), TenantExtendInfo.class);
            tenantVO.setExtendInfo(extendInfo);
        }
        return viewVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeStatus(Integer id, Integer status, Long modifyBy) {
        TenantDO tenantDO = new TenantDO();
        tenantDO.setId(id);
        tenantDO.setPublishStatus(status);
        tenantDO.setModifyBy(modifyBy);
        tenantDO.setModifyTime(LocalDateTime.now());
        return tenantMapper.updateById(tenantDO) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean del(Integer id) {
        TenantDO tenantDO = tenantMapper.selectById(id);
        if (PublishStatusEnum.ENABLE.getValue().equals(tenantDO.getPublishStatus()) || !TenantInitEnum.UN_INIT.getValue().equals(tenantDO.getInit())) {
            throw new BusinessException("租户未禁用或者数据未回收");
        }
        if(tenantEnterpriseInfoService.viewByTenantId(id) != null)
            tenantEnterpriseInfoService.delByTenantId(id);
        if(tenantLegalInfoService.viewByTenantId(id) != null)
            tenantLegalInfoService.delByTenantId(id);
        if(tenantBankService.queryByTenantId(id) != null)
            tenantBankService.delByTenantId(id.longValue());
        if (tenantDetailService.listByTenantId(id) !=null && tenantDetailService.listByTenantId(id).size() >0)
            tenantDetailService.delAllByTenantId(id);
        if (tenantMapper.deleteById(id) > 0) {
            return true;
        }

        throw new BusinessException("删除失败");
    }

    /**
     * 有效租户列表
     *
     * @param tenantQuery
     * @return
     */
    @Override
    public Page<TenantVO> list(TenantQuery tenantQuery) {
        QueryWrapper<TenantDO> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(TenantDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .like(StringUtils.isNotBlank(tenantQuery.getName()), TenantDO::getName, tenantQuery.getName())
                .like(StringUtils.isNotBlank(tenantQuery.getContacts()), TenantDO::getContacts, tenantQuery.getContacts())
                .orderByAsc(TenantDO::getSort)
                .orderByDesc(TenantDO::getCreateTime)
        ;
        Page<TenantDO> page = tenantMapper.selectPage(new Page<>(tenantQuery.getPageNum(), tenantQuery.getPageSize()), queryWrapper);
        return BeanUtil.convertPage(page, TenantVO.class);
    }

    /**
     * 使用id查租户
     *
     * @param id
     * @return
     */
    @Override
    public TenantDTO queryTenantById(Integer id) {
        TenantDO tenantDO = this.tenantMapper.selectById(id);
        if (tenantDO == null) {
            return new TenantDTO();
        }
        TenantDTO dto = BeanUtil.convertBean(tenantDO, TenantDTO.class);
        GroupDO group = this.groupService.getById(id);
        if (group != null) {
            dto.setParentName(group.getName());
        }
        if (tenantDO.getAccountBegin() != null) {
            dto.setAccountBegin(DateUtils.parseStr(tenantDO.getAccountBegin(), DateUtils.YYYY_MM_DD));
        }
        if (tenantDO.getAccountEnd() != null) {
            dto.setAccountEnd(DateUtils.parseStr(tenantDO.getAccountEnd(), DateUtils.YYYY_MM_DD));
        }
        if (tenantDO.getPublishStatus() != null) {
            String status = Long.valueOf(1).equals(tenantDO.getPublishStatus()) ? "启用" : "禁用";
            dto.setPublishStatus(status);
        }
        if (tenantDO.getBusinessCategory() != null) {
            DictDTO businessCategory = dictValueService.queryDictLable(DictTypeEnum.TENANT_BUSINESS_CATEGORY.getValue(), tenantDO.getBusinessCategory().toString());
            if (businessCategory != null) {
                dto.setBusinessCategory(businessCategory.getLabel());
            }
        }
        if (tenantDO.getTenantType() != null) {
            DictDTO tenantType = dictValueService.queryDictLable(DictTypeEnum.TENANT_TYPE.getValue(), tenantDO.getTenantType().toString());
            if (tenantType != null) {
                dto.setTenantType(tenantType.getLabel());
            }
        }
        if (tenantDO.getLogo() != null) {
            dto.setLogoFullPath(UrlUtils.addUrlDomainName(fileOssProp.getHost(), dto.getLogo()));
        }
        if(StringUtils.isNotEmpty(tenantDO.getExtendInfoJson())){
            TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantDO.getExtendInfoJson(), TenantExtendInfo.class);
            dto.setExtendInfo(extendInfo);
        }
        return dto;
    }
    /**
     * 使用id查租户
     *
     * @param id
     * @return
     */
    @Override
    public String queryTenantIndustryById(Integer id) {
        TenantDO tenantDO = this.tenantMapper.selectById(id);
        if(tenantDO == null) return "";
        return tenantDO.getIndustry();
    }
    @Override
    public List<TenantListDTO> queryUserTenantsByIds(List<Integer> ids) {

        //根据租户id查询租户信息
        List<TenantDO> tenantDOS = tenantMapper.selectList(new LambdaQueryWrapper<>(TenantDO.class)
                .eq(TenantDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(TenantDO::getInit, TenantInitEnum.INITED.getValue())
                .in(TenantDO::getId, ids)
                .orderByAsc(TenantDO::getSort)
                .orderByDesc(TenantDO::getCreateTime)
        );

        if (Collections3.isEmpty(tenantDOS)) {
            return Collections3.emptyList();
        }
        List<TenantListDTO> tenantListVOS = JsonUtils.jsonToList(tenantDOS, TenantListDTO.class);
        //封装返回
        Map<Integer, String> tenantTypeMap = dictValueService.queryDictByType(DictTypeEnum.TENANT_TYPE.getValue())
                .stream().collect(Collectors.toMap(dictDTO -> Integer.valueOf(dictDTO.getValue()), DictDTO::getLabel, (s, a) -> a));

        Map<Integer, String> tenantBusinessCategoryMap = dictValueService.queryDictByType(DictTypeEnum.TENANT_BUSINESS_CATEGORY.getValue())
                .stream().collect(Collectors.toMap(dictDTO -> Integer.valueOf(dictDTO.getValue()), DictDTO::getLabel, (s, a) -> a));
        tenantListVOS.stream().forEach(tenantDTO -> {
            tenantDTO.setTenantTypeName(null != tenantTypeMap.get(tenantDTO.getTenantType()) ? tenantTypeMap.get(tenantDTO.getTenantType()) : "");
            tenantDTO.setBusinessCategoryName(null != tenantBusinessCategoryMap.get(tenantDTO.getBusinessCategory()) ? tenantBusinessCategoryMap.get(tenantDTO.getBusinessCategory()) : "");
            if (LocalDate.now().isBefore(DateUtil.strToLocalDate(tenantDTO.getAccountBegin())) || LocalDate.now().isAfter(DateUtil.strToLocalDate(tenantDTO.getAccountEnd())) || !tenantDTO.getInit().equals(TenantInitEnum.INITED.getValue())) {
                tenantDTO.setPublishStatus(PublishStatusEnum.DISABLE.getValue());
            }
            if(StringUtils.isNotEmpty(tenantDTO.getExtendInfoJson())){
                TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantDTO.getExtendInfoJson(), TenantExtendInfo.class);
                tenantDTO.setExtendInfo(extendInfo);
            }
        });
        return tenantListVOS;
    }

    @Override
    public List<TenantListDTO> queryEffectiveTenants() {
        //根据租户id查询租户信息
        List<TenantDO> tenantDOS = tenantMapper.selectList(new LambdaQueryWrapper<>(TenantDO.class)
                .eq(TenantDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(TenantDO::getInit, TenantInitEnum.INITED.getValue())
                .orderByAsc(TenantDO::getSort)
                .orderByDesc(TenantDO::getCreateTime)
        );
        if (Collections3.isEmpty(tenantDOS)) {
            return Collections3.emptyList();
        }
        List<TenantListDTO> tenantListVOS = JsonUtils.jsonToList(tenantDOS, TenantListDTO.class);
        //封装返回
        Map<Integer, String> tenantTypeMap = dictValueService.queryDictByType(DictTypeEnum.TENANT_TYPE.getValue())
                .stream().collect(Collectors.toMap(dictDTO -> Integer.valueOf(dictDTO.getValue()), DictDTO::getLabel, (s, a) -> a));

        Map<Integer, String> tenantBusinessCategoryMap = dictValueService.queryDictByType(DictTypeEnum.TENANT_BUSINESS_CATEGORY.getValue())
                .stream().collect(Collectors.toMap(dictDTO -> Integer.valueOf(dictDTO.getValue()), DictDTO::getLabel, (s, a) -> a));
        tenantListVOS.stream().forEach(tenantDTO -> {
            tenantDTO.setTenantTypeName(null != tenantTypeMap.get(tenantDTO.getTenantType()) ? tenantTypeMap.get(tenantDTO.getTenantType()) : "");
            tenantDTO.setBusinessCategoryName(null != tenantBusinessCategoryMap.get(tenantDTO.getBusinessCategory()) ? tenantBusinessCategoryMap.get(tenantDTO.getBusinessCategory()) : "");
            if (LocalDate.now().isBefore(DateUtil.strToLocalDate(tenantDTO.getAccountBegin())) || LocalDate.now().isAfter(DateUtil.strToLocalDate(tenantDTO.getAccountEnd())) || !tenantDTO.getInit().equals(TenantInitEnum.INITED.getValue())) {
                tenantDTO.setPublishStatus(PublishStatusEnum.DISABLE.getValue());
            }
            if(StringUtils.isNotEmpty(tenantDTO.getExtendInfoJson())){
                TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantDTO.getExtendInfoJson(), TenantExtendInfo.class);
                tenantDTO.setExtendInfo(extendInfo);
            }
        });
        return tenantListVOS;
    }

    @Override
    @Transactional
    public Boolean modifyTenant(com.ibeeking.gmc.global.api.common.param.TenantParam tenantParam) {
        TenantDO param = BeanUtil.convertBean(tenantParam, TenantDO.class);
        param.setModifyTime(LocalDateTime.now());
        if(tenantParam.getExtendInfo() != null){
            String extendInfoStr = JsonUtils.toJsonStr(tenantParam.getExtendInfo());
            param.setExtendInfoJson(extendInfoStr);
        }
        return this.tenantMapper.updateById(param) > 0;
    }

    @Override
    @Transactional
    public Boolean updateTenantExtendInfo(TenantExtendInfo extendInfo) {
        Integer tenantId = extendInfo.getTenantId();
        String extendInfoJson = JsonUtils.toJsonStr(extendInfo);
        LambdaQueryWrapper<TenantDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TenantDO::getId, tenantId);
        TenantDO entityDO = new TenantDO();
        entityDO.setId(tenantId);
        entityDO.setExtendInfoJson(extendInfoJson);
        return this.tenantMapper.update(entityDO, queryWrapper) >0;
    }

    @Override
    public List<Integer> queryTenantIds() {
        List<TenantDO> tenantDos = tenantMapper.selectList(new LambdaQueryWrapper<>(TenantDO.class)
                .eq(TenantDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(TenantDO::getInit, TenantInitEnum.INITED.getValue())
        );
        if (Collections3.isEmpty(tenantDos)) {
            return Collections3.emptyList();
        }
        return tenantDos.stream().filter(tenantDO -> checkExpire(tenantDO.getAccountBegin(), tenantDO.getAccountEnd())).map(TenantDO::getId).collect(Collectors.toList());
    }

    @Override
    public List<OperatorDTO> queryByUserIds(Integer tenantId, List<Long> userIds) {
        List<TenantUserPO> userPos = tenantMapper.queryByUserIds(tenantId, userIds);
        List<OperatorDTO> userInfoDTOS = JsonUtils.jsonToList(userPos, OperatorDTO.class);
        userInfoDTOS.stream().filter(operatorDTO -> StringUtils.isNotBlank(operatorDTO.getImage())).forEach(operatorDTO -> operatorDTO.setImage(fileOssProp.getHost().concat(operatorDTO.getImage())));
        return userInfoDTOS;
    }

    @Override
    public List<TenantEffectiveVO> effectiveList(TenantEffectiveQuery query) {
        List<TenantDO> tenantDos = tenantMapper.selectList(new LambdaQueryWrapper<>(TenantDO.class)
                .orderByAsc(TenantDO::getSort)
                .orderByDesc(TenantDO::getCreateTime)
                .eq(TenantDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(TenantDO::getInit, TenantInitEnum.INITED.getValue())
                .le(TenantDO::getAccountBegin, LocalDate.now())
                .ge(TenantDO::getAccountEnd, LocalDate.now())
                .eq(null != query.getTenantType(), TenantDO::getTenantType, query.getTenantType())
                .likeRight(StringUtils.isNotBlank(query.getCode()), TenantDO::getCode, query.getCode())
                .likeRight(StringUtils.isNotBlank(query.getName()), TenantDO::getName, query.getName())
                .likeRight(StringUtils.isNotBlank(query.getSempleName()), TenantDO::getSempleName, query.getSempleName())
                .likeRight(StringUtils.isNotBlank(query.getCompany()), TenantDO::getCompany, query.getCompany())
                .in(!Collections3.isEmpty(query.getIds()), TenantDO::getId, query.getIds())
        );
        return JsonUtils.jsonToList(tenantDos, TenantEffectiveVO.class);
    }

    @Override
    public List<String> queryPermissionIdsByTenantId(Integer tenantId, String module) {
        ThreadContext.put(LogConstant.TENANT_ID, String.valueOf(tenantId));
        try {
            ResponseResult<List<Long>> menus = upmsTenantUserClient.menus(module);
            if (null == menus || null == menus.getData()) {
                return Collections3.emptyList();
            }
            return menus.getData().parallelStream().map(String::valueOf).collect(Collectors.toList());
        } finally {
            ThreadContext.remove(LogConstant.TENANT_ID);
        }
    }

    @Override
    public Boolean configurePermission(TenantPermissionParam param) {
        Map<String, List<Long>> paramMap = new HashMap<>();
        for (TenantPermissionItem tenantPermissionItem : param.getTenantPermissionItems()) {
            if (paramMap.containsKey(tenantPermissionItem.getModule())) {
                paramMap.get(tenantPermissionItem.getModule()).addAll(Arrays.asList(tenantPermissionItem.getPermissionIds()));
            } else {
                paramMap.put(tenantPermissionItem.getModule(), new ArrayList<>(Arrays.asList(tenantPermissionItem.getPermissionIds())));
            }
        }
        List<PermissionParam> params = new ArrayList<>();
        for (Map.Entry<String, List<Long>> map : paramMap.entrySet()) {
            //获取当前模块所有菜单
            map.getValue().stream().forEach(s -> {
                PermissionParam permissionParam = new PermissionParam();
                permissionParam.setModule(map.getKey());
                permissionParam.setId(s);
                permissionParam.setCreateBy(Long.valueOf(ThreadContext.get(LogConstant.USER_ID)));
                params.add(permissionParam);
            });
        }
        ThreadContext.put(LogConstant.TENANT_ID, String.valueOf(param.getTenantId()));
        try {
            ResponseResult<Boolean> responseResult1 = upmsTenantUserClient.configurePermission(params);
            if (null == responseResult1 || null == responseResult1.getData()) {
                return false;
            }
            return responseResult1.getData();
        } finally {
            ThreadContext.remove(LogConstant.TENANT_ID);
        }
    }

    @CacheQuery(cacheName = RedisKeyConstant.TENANT_INFO_CODE, key = "#code", expires = RedisKeyConstant.DAY)
    @Override
    public TenantDTO queryTenantByCode(String code) {
        TenantDO tenantDO = tenantMapper.selectOne(new LambdaQueryWrapper<>(TenantDO.class)
                .eq(TenantDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(TenantDO::getInit, TenantInitEnum.INITED.getValue())
                .eq(TenantDO::getCode, code)
        );
        TenantDTO entityDTO = BeanUtil.convertBean(tenantDO, TenantDTO.class);
        if(StringUtils.isNotEmpty(tenantDO.getExtendInfoJson())){
            TenantExtendInfo extendInfo = JsonUtils.fromJson(tenantDO.getExtendInfoJson(), TenantExtendInfo.class);
            entityDTO.setExtendInfo(extendInfo);
        }
        return entityDTO;
    }

    @Override
    public Boolean initTenant(Long userId, Integer tenantId, Long datasourceId) {
        if(null == datasourceId) throw new BusinessException("没有配置租户数据源");
        getBean().insertAndUpdateTenantDatasource(tenantId, datasourceId);
        TenantDO tenantDO = tenantMapper.selectById(tenantId);
        if(tenantDO == null) throw new BusinessException("租户信息未创建");
        LogUtils.info("====================开始租户[{}]数据初始化......=====================",tenantDO.getName());
        String prefixKey = RedisKeyConstant.TENANT_INFO_INIT_LOG.concat(tenantId.toString());
        redisUtils.del(prefixKey);
        deleteTenantInitLog(tenantId);
        writeTenantInitLog(tenantId, "......开始租户[" + tenantDO.getName() +"]数据初始化");
        try {
            //校验当前租户的信息
            Boolean valid = checkTenantInfoValidate(tenantId);
            //初始化租户管理员账号
            TenantUserDTO adminAccount = initTenantAdminAccount(tenantId);
            //从模板库初始化租户数据
            Boolean initData = initTenantData(tenantId, adminAccount);
            //创建当前租户的定时任务
            Boolean job = initTenantTimeTaskJobList(tenantId);
            LogUtils.info("====================租户[{}]数据初始化....完成！=====================",tenantDO.getName());
            writeTenantInitLog(tenantId, "......恭喜，租户[" + tenantDO.getName() +"]数据初始化....完成！");
            return true;
        } catch (Exception e) {
            getBean().changeInit(tenantId, TenantInitEnum.UN_INIT.getValue());
            writeTenantInitLog(tenantId, "......租户[" + tenantDO.getName() +"]数据初始化....失败！");
            throw new BusinessException("初始化租户数据失败");
        }
    }

    @Override
    public Boolean changeInit(Integer tenantId, Integer status) {
        TenantDO tenantDO = new TenantDO();
        tenantDO.setId(tenantId);
        tenantDO.setInit(status);
        tenantDO.setModifyTime(LocalDateTime.now());
        return tenantMapper.updateById(tenantDO) > 0;
    }

    @Override
    public Boolean recovery(Long userId, Integer tenantId) {
        LogUtils.info("====================回收租户数据......=====================");
        TenantDO tenantDO = tenantMapper.selectById(tenantId);
        if (null == tenantDO) throw new BusinessException("读取租户数据失败");
        String industry = tenantDO.getIndustry();
        if(StringUtils.isEmpty(industry)) throw new BusinessException("读取租户信息失败");
        if(TenantInitEnum.INITING.getValue().equals(tenantDO.getInit()) ) throw new BusinessException("租户初始化未完成，不能回收！");
        if(PublishStatusEnum.ENABLE.getValue().equals(tenantDO.getPublishStatus()))  throw new BusinessException("租户状态处于启用状态，不能回收！");
        //删除定时任务
        clearTenantTimeTaskJobList(tenantId);
        //查询模板数据源，
        TenantDatasourceDO tenantDatasourceRelDO =  queryTenantDatasourceByTenantId(tenantId);
        Long datasourceId = tenantDatasourceRelDO.getDatasourceId();
        DatasourceConfigBO tenantDatasource = templateDatabaseConfigServiceImpl.queryById(datasourceId);
        if (tenantDatasource == null)  return false;
        //查询模板数据库
        List<DatabaseTemplateBO> databaseTemplateList = templateDatabaseServiceImpl.queryByIndustry(industry);;
        if (Collections3.isEmpty(databaseTemplateList))  return false;
        LogUtils.info("====================删除租户数据库......=====================");
        //先查询数据库创建
        Connection tenantDatasourceConnect = DatasourceConfigServiceImpl.getConnection(tenantDatasource.getHost(), tenantDatasource.getPort(), tenantDatasource.getUserName(), tenantDatasource.getPassword());
        if (null == tenantDatasourceConnect)  return false;
        try {
            // 关闭自动提交
            tenantDatasourceConnect.setAutoCommit(false);
            Statement stmt = tenantDatasourceConnect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            for (int j = 0; j < databaseTemplateList.size(); j++) {
                DatabaseTemplateBO databaseTemplate = databaseTemplateList.get(j);
                StringBuffer dropTenantDatabaseScriptBUffer = new StringBuffer();
                dropTenantDatabaseScriptBUffer.append("DROP DATABASE IF EXISTS `")
                        .append(getNewDbNamePrefix(databaseTemplate.getDbName()))
                        .append(tenantId).append("`");
                stmt.addBatch(dropTenantDatabaseScriptBUffer.toString());
                LogUtils.info(">>>>>>RECOVER DB SCRIPT:{}",dropTenantDatabaseScriptBUffer.toString());
            }
            //3. 执行数据脚本
            stmt.executeBatch();
            tenantDatasourceConnect.commit();
            tenantDatasourceConnect.close();
        } catch (Exception ex) {
            LogUtils.error(LogClassifyEnum.ERROR_LOG, "回收租户数据失败", ex);
            getBean().changeInit(tenantId, TenantInitEnum.INIT_FAIL.getValue());
            return false;
        }
        getBean().deleteTenantDatasource(tenantId);
        LogUtils.info("====================回收租户数据....完成，更新租住状态=====================");
        if (!getBean().changeInit(tenantId, TenantInitEnum.UN_INIT.getValue())) {
            return false;
        }
        return true;
    }
    /**
     * 初始化租户数据
     *
     * @param tenantId
     * @return
     */
    private Boolean checkTenantInfoValidate(Integer tenantId) {
        String mobile = "";
        TenantDO tenantDO = tenantMapper.selectById(tenantId);
        writeTenantInitLog(tenantId, "......1-检查租户是否满足初始化要求");
        if (redisUtils.tryLock(INIT_TENANT_LOCK + tenantId)) {
            try {
                mobile = tenantDO.getMobile();
                if (StringUtils.isBlank(mobile))  throw new BusinessException("请配置租户管理员手机号");
                String name = tenantDO.getContacts();
                if (StringUtils.isBlank(name))  throw new BusinessException("请配置租户联系人，联系人作为初始化管理员");
                //查询是否存在商户下有该手机号
                ResponseResult<TenantUserDTO> tenantUserDTOResponseResult = upmsTenantUserClient.queryShopUserByMobile(mobile);
                if (tenantUserDTOResponseResult.getData() != null)  throw new BusinessException("该手机号已是商户员工，请删除后再初始化租户");
                if (PublishStatusEnum.DISABLE.getValue().equals(tenantDO.getPublishStatus()))  throw new BusinessException("请先启用当前租户再初始化");
                if (TenantInitEnum.INITING.getValue().equals(tenantDO.getInit()))  throw new BusinessException("租户正在初始化，请不要重复操作");
                if (TenantInitEnum.INITED.getValue().equals(tenantDO.getInit()))  throw new BusinessException("租户已初始化完成，请不要重复操作");
                // 更新租户初始化状态为初始化进行中
                Boolean initStaus = getBean().changeInit(tenantId, TenantInitEnum.INITING.getValue());
                if(!initStaus) return false;
            } finally {
                redisUtils.unlock(INIT_TENANT_LOCK + tenantId);
            }
        }
        if (StringUtils.isBlank(mobile))  throw new BusinessException("租户管理员账号不能为空");
        return true;
    }

    /**
     * 初始化租户Job
     * @param tenantId
     * @return
     */
    private Boolean initTenantTimeTaskJobList(Integer tenantId) {
        writeTenantInitLog(tenantId, "......2-初始化所有租户端的定时Job任务");
        TenantDO tenantDO = tenantMapper.selectById(tenantId);
        if(tenantDO == null) throw new BusinessException("读取租户信息失败");
        String industry = tenantDO.getIndustry();
        if(StringUtils.isEmpty(industry)) throw new BusinessException("读取租户信息失败");
        List<TimeTaskVO> timeTaskVOS  = timeTaskServiceImpl.listByIndustry(industry);
        if(Collections3.isNotEmpty(timeTaskVOS)){
            timeTaskVOS.stream().forEach(s->{
                writeTenantInitLog(tenantId, "......初始化定时Job任务:"+s.getJobName()+"");
                try {
                    String executorJobClazz = s.getJobClazz();
                    String jobCreateMethod = s.getJobCreateMethod();
                    Object jobClazzObj = SpringBeanUtil.getBean(ClassUtils.getClass(executorJobClazz));
                    TimeTaskJobParam jobPram = new TimeTaskJobParam();
                    jobPram.setTenantId(tenantId);
                    jobPram.setIndustry(industry);
                    jobPram.setHandler(s.getExecutorHandler());
                    Method jobMethod = ReflectionUtils.findMethod(jobClazzObj.getClass(), jobCreateMethod, TimeTaskJobParam.class);
                    Object result = ReflectionUtils.invokeMethod(jobMethod, jobClazzObj, jobPram);
                    //Object result = Reflections.invokeMethodByName(jobClazzObj, jobCreateMethod, new Object[]{jobPram});
                    LogUtils.info("=============初始化定时Job任务:"+s.getJobName()+"...." + result.toString() + "==============");
                }catch(Exception ex){
                    LogUtils.info("创建Job任务出错：{}",ex);
                }
            });
        }
        return true;
    }
    /**
     * 初始化租户Job
     * @param tenantId
     * @return
     */
    private Boolean clearTenantTimeTaskJobList(Integer tenantId) {
        LogUtils.info("====================清除所有租户端的定时Job任务....=====================");
        TenantDO tenantDO = tenantMapper.selectById(tenantId);
        if(tenantDO == null) throw new BusinessException("读取租户信息失败");
        String industry = tenantDO.getIndustry();
        if(StringUtils.isEmpty(industry)) throw new BusinessException("读取租户信息失败");
        List<TimeTaskVO> timeTaskVOS  = timeTaskServiceImpl.listByIndustry(industry);
        if(Collections3.isNotEmpty(timeTaskVOS)){
            timeTaskVOS.stream().forEach(s->{
                writeTenantInitLog(tenantId, "......清除定时Job任务:"+s.getJobName()+"");
                try {
                    String executorJobClazz = s.getJobClazz();
                    String jobDelMethod = s.getJobDelMethod();
                    Object jobClazzObj = SpringBeanUtil.getBean(ClassUtils.getClass(executorJobClazz));
                    TimeTaskJobParam jobPram = new TimeTaskJobParam();
                    jobPram.setTenantId(tenantId);
                    jobPram.setIndustry(industry);
                    jobPram.setHandler(s.getExecutorHandler());
                    Method jobMethod = ReflectionUtils.findMethod(jobClazzObj.getClass(), jobDelMethod, TimeTaskJobParam.class);
                    Object result = ReflectionUtils.invokeMethod(jobMethod,jobClazzObj, jobPram);
                    //Object result = Reflections.invokeMethodByName(jobClazzObj, jobDelMethod, new Object[]{jobPram});
                    LogUtils.info("=============清除定时Job任务:"+s.getJobName()+"...." + result.toString() + "==============");
                }catch(Exception ex){
                    LogUtils.info("创建Job任务出错：{}",ex);
                }
            });
        }
        return true;
    }
    /**
     * 初始化租户Job
     * @param tenantId
     * @return
     */
    private TenantUserDTO initTenantAdminAccount(Integer tenantId) {
        //查询当前账号是否已存在，存在返回租户信息
        TenantDO tenant = tenantMapper.selectById(tenantId);
        if(tenant == null) throw new BusinessException("租户信息未创建");
        List<Integer> tenantIds = getBean().queryTenantIds();
        writeTenantInitLog(tenantId, "......3-初始化租户管理员用户");
        TenantUserDTO adminAccount = new TenantUserDTO();
        String contactMobile = tenant.getMobile();
        String contactName = tenant.getContacts();
        if(Collections3.isNotEmpty(tenantIds)) {
            ResponseResult<TenantUserDTO> responseResult = upmsTenantUserClient.queryByMobile(contactMobile);
            if (null == responseResult || !ResponseCodeEnum.SUCCESS.getCode().equals(responseResult.getCode())) {
                throw new BusinessException("账号查询异常");
            }
            adminAccount = responseResult.getData();
            adminAccount.setUserCode(StringUtils.isEmpty(adminAccount.getUserCode())? contactMobile:adminAccount.getUserCode());
            adminAccount.setName(StringUtils.isEmpty(adminAccount.getName())? contactName:adminAccount.getName());
            adminAccount.setMobile(StringUtils.isEmpty(adminAccount.getMobile())? contactMobile:adminAccount.getMobile());
            adminAccount.setEmail(StringUtils.isEmpty(adminAccount.getEmail())? tenant.getEmail():adminAccount.getEmail());
            adminAccount.setTel(StringUtils.isEmpty(adminAccount.getTel())? tenant.getPhone():adminAccount.getTel());
        }else{

            adminAccount.setId(GenerateId.generateId());
            adminAccount.setUserCode(contactMobile);
            adminAccount.setName(contactName);
            adminAccount.setMobile(contactMobile);
            adminAccount.setSex(SexEnum.UNKNOWN.getCode());
            adminAccount.setEmail(tenant.getEmail());
            adminAccount.setTel(tenant.getPhone());
            adminAccount.setImage(DefaultPathConstant.DEFAULT_USER_HEAD_IMAGE);
            adminAccount.setPassword(passwordEncoder.encode("123456"));
        }
        if (StringUtils.isBlank(adminAccount.getName())) {
            adminAccount.setName(StringUtils.isNotBlank(contactName) ? contactName : contactMobile);
        }
        return adminAccount;
    }

    /**
     * 初始化租户数据
     *
     * @param tenantId
     * @return
     */
    private Boolean initTenantData(Integer tenantId, TenantUserDTO tenantAdminAccount) {
        //查询模板数据源，
        writeTenantInitLog(tenantId, "......4-检查数据库模板数据源");
        //拼装初始化脚本
        Map<Long, List<String>> scriptsMaps = assembleDatabaseCreateScript(tenantId, tenantAdminAccount);
        //执行脚本
        boolean loadScript = LoadDatabaseCreateScript(tenantId, scriptsMaps);
        //跟新租户初始化状态
        writeTenantInitLog(tenantId, "......7-更新租户初始化状态");
        if (!getBean().changeInit(tenantId, TenantInitEnum.INITED.getValue())) {
            return false;
        }
        return true;
    }

    /**
     * 装配数据库创建脚本
     * @param tenantId
     * @param tenantUserAccount
     * @return
     */
    private Map<Long, List<String>> assembleDatabaseCreateScript(Integer tenantId, TenantUserDTO tenantUserAccount) {
        Map<Long, List<String>> resultAssembleScriptMap = new HashMap<>();
        TenantDO tenantDO = tenantMapper.selectById(tenantId);
        if(tenantDO == null) throw new BusinessException("读取租户信息失败");
        String industry = tenantDO.getIndustry();
        if(StringUtils.isEmpty(industry)) throw new BusinessException("租户行业信息未配置！");
        //查询模板数据库
        DatasourceConfigBO templateDatasource = templateDatabaseConfigServiceImpl.queryDatabseTemplateDatasource();
        if (templateDatasource == null)  throw new BusinessException("模板数据源不存在");
        writeTenantInitLog(tenantId, "......5-装配数据库创建脚本");
        List<DatabaseTemplateBO> databaseTemplateList = templateDatabaseServiceImpl.queryByIndustry(industry);
        if (Collections3.isEmpty(databaseTemplateList))  throw new BusinessException("模板数据库不存在");
        LogUtils.info("6-读取行业模板：{}", JsonUtils.toJsonStr(databaseTemplateList));
        Connection templateDatasourceConnect = DatasourceConfigServiceImpl.getConnection(templateDatasource.getHost(), templateDatasource.getPort(), templateDatasource.getUserName(), templateDatasource.getPassword());
        if (null == templateDatasourceConnect)  throw new BusinessException("模板数据源连接失败");
        List<String> assembleScriptList = new ArrayList<>();
        try {
            //>>>>>>>>>>> 数据库Database创建脚本<<<<<<<<<<<<<<<<<<<<<
            writeTenantInitLog(tenantId, "......数据库创建脚本");
            for (int j = 0; j < databaseTemplateList.size(); j++) {
                DatabaseTemplateBO databaseTemplate = databaseTemplateList.get(j);
                StringBuffer databaseCreateScriptBuffer = new StringBuffer();
                databaseCreateScriptBuffer.append("DROP DATABASE IF EXISTS `")
                        .append(getNewDbNamePrefix(databaseTemplate.getDbName()))
                        .append(tenantId).append("`");
                assembleScriptList.add(databaseCreateScriptBuffer.toString());
                databaseCreateScriptBuffer.delete(0, databaseCreateScriptBuffer.length());
                databaseCreateScriptBuffer.append("CREATE DATABASE ")
                        .append(getNewDbNamePrefix(databaseTemplate.getDbName()))
                        .append(tenantId)
                        .append(" DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
                assembleScriptList.add(databaseCreateScriptBuffer.toString());
            }
            // 关闭自动提交
            templateDatasourceConnect.setAutoCommit(false);
            Statement stmt = templateDatasourceConnect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            Statement viewCreateStmt = templateDatasourceConnect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            Statement industrFildCheckStmt = templateDatasourceConnect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            //>>>>>>>>>>> 表Table创建脚本<<<<<<<<<<<<<<<<<<<<<
            writeTenantInitLog(tenantId, "......表创建脚本");
            for (int j = 0; j < databaseTemplateList.size(); j++) {
                DatabaseTemplateBO databaseTemplate = databaseTemplateList.get(j);
                StringBuffer switchDatabaseScriptBuffer = new StringBuffer();
                switchDatabaseScriptBuffer.append("USE ")
                        .append(databaseTemplate.getDbName());
                stmt.execute(switchDatabaseScriptBuffer.toString());
                templateDatasourceConnect.commit();
                ResultSet tablesList = stmt.executeQuery("SHOW FULL TABLES");
                //表Table脚本
                while (tablesList.next()) {
                    StringBuffer tableCreateScriptBuffer = new StringBuffer();
                    if(!tablesList.getString(2).equalsIgnoreCase(TableType.VIEW.value())) {
                        tableCreateScriptBuffer.append("CREATE TABLE ")
                                .append(getNewDbNamePrefix(databaseTemplate.getDbName()))
                                .append(tenantId)
                                .append(".")
                                .append(tablesList.getString(1))
                                .append(" LIKE ")
                                .append(databaseTemplate.getDbName())
                                .append(".")
                                .append(tablesList.getString(1));
                        assembleScriptList.add(tableCreateScriptBuffer.toString());
                        LogUtils.info(">>>>>>TABLE SQL SCRIPT:{}",tableCreateScriptBuffer.toString());
                        if (!"undo_log".equals(tablesList.getString(1))) {
                            tableCreateScriptBuffer.delete(0, tableCreateScriptBuffer.length());
                            StringBuffer industrFildCheckScriptBuffer = new StringBuffer();
                            industrFildCheckScriptBuffer.append(" SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS ");
                            industrFildCheckScriptBuffer.append(" WHERE TABLE_SCHEMA='" + databaseTemplate.getDbName() + "' ");
                            industrFildCheckScriptBuffer.append(" AND TABLE_NAME='" + tablesList.getString(1) + "' ");
                            industrFildCheckScriptBuffer.append(" AND COLUMN_NAME='industry' ");
                            ResultSet industrFildCheckRS = industrFildCheckStmt.executeQuery(industrFildCheckScriptBuffer.toString());
                            if(industrFildCheckRS.next()) {
                                tableCreateScriptBuffer.append("INSERT INTO ")
                                        .append(getNewDbNamePrefix(databaseTemplate.getDbName()))
                                        .append(tenantId)
                                        .append(".")
                                        .append(tablesList.getString(1))
                                        .append(" SELECT * FROM ")
                                        .append(databaseTemplate.getDbName())
                                        .append(".")
                                        .append(tablesList.getString(1))
                                        .append(" WHERE INDUSTRY='" + industry + "'");
                            }else{
                                tableCreateScriptBuffer.append("INSERT INTO ")
                                        .append(getNewDbNamePrefix(databaseTemplate.getDbName()))
                                        .append(tenantId)
                                        .append(".")
                                        .append(tablesList.getString(1))
                                        .append(" SELECT * FROM ")
                                        .append(databaseTemplate.getDbName())
                                        .append(".")
                                        .append(tablesList.getString(1));
                            }
                            LogUtils.info(">>>>>>TABLE DATA SCRIPT:{}",tableCreateScriptBuffer.toString());
                            assembleScriptList.add(tableCreateScriptBuffer.toString());
                        }
                    }else if(tablesList.getString(2).equalsIgnoreCase(TableType.VIEW.value())) {
                        //视图View脚本
//                        ResultSet viewRs = viewCreateStmt.executeQuery("SHOW CREATE VIEW " + tablesList.getString(1));
//                        if(viewRs.next()){
//                            String viewCreate = viewRs.getString(2);
//                            if(StringUtils.isNotEmpty(viewCreate)) {
//                                assembleScriptList.add(viewCreate);
//                                LogUtils.info(">>>>>>VIEW SQL SCRIPT:{}",viewCreate);
//                            }
//                        }
                    }
                }
                //视图View脚本
//                while (tablesList.next()) {
//                    if(tablesList.getString(2).equalsIgnoreCase(TableType.VIEW.value())) {
//                        ResultSet viewRs = stmt.executeQuery("SHOW CREATE VIEW " + tablesList.getString(1));
//                        if(viewRs.next()){
//                            String viewCreate = viewRs.getString(2);
//                            if(StringUtils.isNotEmpty(viewCreate)) {
//                                assembleScriptList.add(viewCreate);
//                                LogUtils.info(">>>>>>VIEW SQL SCRIPT:{}",viewCreate);
//                            }
//                        }
//                    }
//                }
            }
            //判断是否是upms库模板 租户管理员账号期初数据
            writeTenantInitLog(tenantId, "......初始化数据导入脚本");
            for (DatabaseTemplateBO databaseTemplate : databaseTemplateList) {
                if (databaseTemplate.getDbName().contains("base_upms_")) {
                    StringBuffer industryFildScriptBuffer = new StringBuffer();
                    industryFildScriptBuffer.append(" SELECT ID FROM ");
                    industryFildScriptBuffer.append(databaseTemplate.getDbName());
                    industryFildScriptBuffer.append(".");
                    industryFildScriptBuffer.append("upms_tenant_role");
                    industryFildScriptBuffer.append(" WHERE INDUSTRY='" + industry + "' ");
                    industryFildScriptBuffer.append(" AND CODE='" + RoleConstant.ADMINISTRATOR + "' ");
                    industryFildScriptBuffer.append(" AND PUBLISH_STATUS=" + PublishStatusEnum.ENABLE.getValue() + " ");
                    Statement industrUpmsDbStmt = templateDatasourceConnect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
                    ResultSet industryFildCheckRS = industrUpmsDbStmt.executeQuery(industryFildScriptBuffer.toString());
                    Long roleId = DefaultPrimaryKeyIdConstant.PRIMARY_KEY_ID_TENANT_SYSTEMADMIN_ROLE;
                    if(industryFildCheckRS.next()) {
                        roleId = industryFildCheckRS.getLong(1);
                    }
                    assembleInitUpmsDBScript(tenantId, tenantUserAccount, roleId, assembleScriptList);
                }
                if (databaseTemplate.getDbName().contains("base_org_")) {
                   assembleInitOrgDBScript(tenantId, tenantDO, assembleScriptList);
                }
            }
            templateDatasourceConnect.close();
        } catch (Exception ex) {
            writeTenantInitLog(tenantId, "......脚本装配出错！");
            LogUtils.error(">>>>>>脚本装配出错{}", ex.getMessage());
            throw new BusinessException("加载脚本失败");
        } finally {
            if (null != templateDatasourceConnect) {
                try {
                    templateDatasourceConnect.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        resultAssembleScriptMap.put(templateDatasource.getId(), assembleScriptList);
        return resultAssembleScriptMap;
    }

    /*
    * 初始化UPMS数据库，创建超级用户账号
    */
    private void assembleInitUpmsDBScript(Integer tenantId, TenantUserDTO tenantUserAccount, Long roleId, List<String> assembleScriptList){
        String insertSql = "INSERT INTO ";
        insertSql = insertSql.concat("base_upms_");
        StringBuffer sysAdminCreateScriptBuffer = new StringBuffer(insertSql);
        sysAdminCreateScriptBuffer.append(tenantId)
                .append(".upms_tenant_user (id,user_code,name,password,nick_name,image,mobile,tel,sex,email,description,job,publish_status) VALUE ")
                .append("(")
                .append(tenantUserAccount.getId()).append(",'")
                .append(tenantUserAccount.getUserCode()).append("','")
                .append(tenantUserAccount.getName()).append("','")
                .append(tenantUserAccount.getPassword()).append("','")
                .append(tenantUserAccount.getNickName()).append("','")
                .append(tenantUserAccount.getImage()).append("','")
                .append(tenantUserAccount.getMobile()).append("','")
                .append(tenantUserAccount.getTel()).append("',")
                .append(tenantUserAccount.getSex()).append(",'")
                .append(tenantUserAccount.getEmail()).append("','")
                .append(UserConstant.SYSTEM_ADMIN).append("',")
                .append(JobStatusEnum.ON_JOB.getCode()).append(",")
                .append(PublishStatusEnum.ENABLE.getValue())
                .append(")");
        assembleScriptList.add(sysAdminCreateScriptBuffer.toString());
        LogUtils.info(">>>>>>ADMIN DATA INIT SCRIPT:{}",sysAdminCreateScriptBuffer.toString());
        StringBuffer userRoleCreateScriptBuffer = new StringBuffer(insertSql);
        userRoleCreateScriptBuffer.append(tenantId)
                .append(".upms_tenant_user_role (id,user_id,role_id) VALUE ")
                .append("(")
                .append(GenerateId.generateId()).append(",")
                .append(tenantUserAccount.getId()).append(",")
                .append(roleId).append(")");
        assembleScriptList.add(userRoleCreateScriptBuffer.toString());
        LogUtils.info(">>>>>>ADMIN ROLE DATA INIT SCRIPT:{}",userRoleCreateScriptBuffer.toString());
    }

    /*
     * 初始化UPMS数据库，创建超级用户账号
     */
    private void assembleInitOrgDBScript(Integer tenantId, TenantDO tenantDO, List<String> assembleScriptList){
        String insertSql = "INSERT INTO ";
        insertSql = insertSql.concat("base_org_");
        StringBuffer sysAdminCreateScriptBuffer = new StringBuffer(insertSql);
        sysAdminCreateScriptBuffer.append(tenantId)
                .append(".department(id,parent_id,code,name,nick_name,leader_id,phone,level,sort,remark,publish_status) VALUE ")
                .append("(")
                .append(tenantDO.getId()).append(",")
                .append(GlobalConstant.PARENT_ID).append(",'")
                .append(tenantDO.getCode()).append("','")
                .append(tenantDO.getName()).append("','")
                .append("',")
                .append("null,'")
                .append("',")
                .append("0,")
                .append("1,'")
                .append(tenantDO.getCompany()).append("',")
                .append(PublishStatusEnum.ENABLE.getValue())
                .append(")");
        assembleScriptList.add(sysAdminCreateScriptBuffer.toString());
    }
    /**
     * 装配数据库创建脚本
     * @param tenantId
     * @param scriptsMap
     * @return
     */
    private Boolean LoadDatabaseCreateScript(Integer tenantId, Map<Long, List<String>> scriptsMap) {
        //执行脚本
        TenantDatasourceDO tenantDatasourceRelDO =  queryTenantDatasourceByTenantId(tenantId);
        Long datasourceId = tenantDatasourceRelDO.getDatasourceId();
        DatasourceConfigBO tenantDatasource = templateDatabaseConfigServiceImpl.queryById(datasourceId);
        if (tenantDatasource == null)  throw new BusinessException("租户数据源不存在");

        writeTenantInitLog(tenantId, "......6-执行数据库创建脚本");
        for (Map.Entry<Long, List<String>> entry : scriptsMap.entrySet()) {
            Connection tenantDatasourceConnect = DatasourceConfigServiceImpl.getConnection(tenantDatasource.getHost(), tenantDatasource.getPort(), tenantDatasource.getUserName(), tenantDatasource.getPassword());
            if (null == tenantDatasourceConnect)  throw new BusinessException("模板数据源连接失败");
            List<String> scripts = entry.getValue();
            try {
                tenantDatasourceConnect.setAutoCommit(false);
                Statement stmt = tenantDatasourceConnect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
                excuteScriptSql(tenantDatasourceConnect, stmt, scripts, true);
            } catch (Exception ex) {
                LogUtils.error("====================执行脚本异常{}....=====================",ex);
                throw new BusinessException("执行脚本异常", ex);
            } finally {
                if (null != tenantDatasourceConnect) {
                    try {
                        tenantDatasourceConnect.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
            }
        }
        return true;
    }

    private void excuteScriptSql(Connection conn, Statement stmt, List<String> scripts, Boolean close) {
        try {
            //1. 执行数据库脚本
            for (String sql : scripts) {
                stmt.addBatch(sql);
            }
            //3. 执行数据脚本
            stmt.executeBatch();
            conn.commit();
            if (close) {
                conn.close();
            }
        } catch (Exception ex) {
            LogUtils.info("====================执行脚本异常{}=====================",ex);
            throw new BusinessException("执行脚本异常", ex);
        } finally {
            if (null != conn && close) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }

    @Override
    public String readTenantInitLog(Long userId, Integer tenantId) {
        try {
            String logFileFullPath = fileConfigProp.getFilePath().concat("/").concat(INIT_PROCESS_LOG);
            File logFile = new File(logFileFullPath);
            if(logFile.exists()){
                return FileUtils.readFileToString(logFile, Charset.defaultCharset());
            }
        }catch(Exception ex){
            return "";
        }
        return "";
    }

    private void writeTenantInitLog(Integer tenantId, String info){
        try {
            if (!FileUtils.existDirs(fileConfigProp.getFilePath())) {
                FileUtils.createDirs(fileConfigProp.getFilePath());
            }
            String logFileFullPath = fileConfigProp.getFilePath().concat("/").concat(INIT_PROCESS_LOG);
            File logFile = new File(logFileFullPath);
            FileUtils.writeStringToFile(logFile, info + "\r\n", Charset.defaultCharset(),true);
        }catch(Exception ex){}
    }

    private void deleteTenantInitLog(Integer tenantId){
        try {
            String logFileFullPath = fileConfigProp.getFilePath().concat("/").concat(INIT_PROCESS_LOG);
            if (FileUtils.existDirs(logFileFullPath)) {
                FileUtils.delete(logFileFullPath);
            }
        }catch(Exception ex){}
    }

    private static String getNewDbNamePrefix(String dbName) {
        return dbName.substring(0, dbName.lastIndexOf("_") + 1);
    }

    private void checkTenant(TenantParam tenantParam) {
        QueryWrapper<TenantDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TenantDO::getSempleName, tenantParam.getSempleName());
        queryWrapper.lambda().ne(tenantParam.getId() != null, TenantDO::getId, tenantParam.getId());
        if (Collections3.isNotEmpty(this.tenantMapper.selectList(queryWrapper))) {
            throw new BusinessException("租户简称不可以重复");
        }
        queryWrapper.clear();
        queryWrapper.lambda().eq(TenantDO::getCode, tenantParam.getCode());
        queryWrapper.lambda().ne(tenantParam.getId() != null, TenantDO::getId, tenantParam.getId());
        if (Collections3.isNotEmpty(this.tenantMapper.selectList(queryWrapper))) {
            throw new BusinessException("租户代码不可以重复");
        }
        String mobile = tenantParam.getMobile();
        if(StringUtils.isNotEmpty(mobile)){
            if(!MobileCheckUtils.checkMobileValid(mobile)){
                throw new BusinessException("手机号不正确，请重新输入!");
            }
        }
        String email = tenantParam.getEmail();
        if(StringUtils.isNotEmpty(email)){
            if(!EmailCheckUtils.checkEmailValid(email)){
                throw new BusinessException("邮箱格式不正确，请重新输入!");
            }
        }
    }

    @Override
    public Boolean insertAndUpdateTenantDatasource(Integer tenantId, Long datasourceId) {
        TenantDatasourceDO tenantDatasourceDO = tenantDatasourceMapper.selectOne(new LambdaQueryWrapper<TenantDatasourceDO>().eq(TenantDatasourceDO::getTenantId, tenantId));
        if(tenantDatasourceDO == null){
            tenantDatasourceDO = new TenantDatasourceDO();
            tenantDatasourceDO.setId(IdGenerator.getId());
            tenantDatasourceDO.setTenantId(tenantId);
            tenantDatasourceDO.setDatasourceId(datasourceId);
            return tenantDatasourceMapper.insert(tenantDatasourceDO) >0;
        }else{
            tenantDatasourceDO.setDatasourceId(datasourceId);
            return tenantDatasourceMapper.updateById(tenantDatasourceDO) >0;
        }
    }

    @Override
    public Boolean deleteTenantDatasource(Integer tenantId) {
        TenantDatasourceDO tenantDatasourceDO = tenantDatasourceMapper.selectOne(new LambdaQueryWrapper<TenantDatasourceDO>().eq(TenantDatasourceDO::getTenantId, tenantId));
        if(tenantDatasourceDO != null){
            return tenantDatasourceMapper.delete(
                    new LambdaQueryWrapper<TenantDatasourceDO>()
                            .eq(TenantDatasourceDO::getTenantId, tenantId)
            ) > 0;
        }
        return true;
    }

    private TenantDatasourceDO queryTenantDatasourceByTenantId(Integer tenantId){
        TenantDatasourceDO entityDO = tenantDatasourceMapper.selectOne(new LambdaQueryWrapper<TenantDatasourceDO>().eq(TenantDatasourceDO::getTenantId, tenantId));
        if(entityDO == null) throw new BusinessException("没有查到租户数据源配置信息!");
        return entityDO;
    }

    public static Boolean checkExpire(LocalDate validityStartDate, LocalDate validityEndDate) {
        LocalDate now = LocalDate.now();
        if (!now.equals(validityStartDate) && DateUtil.compare(now, validityStartDate)) {
            return false;
        }
        if (!now.equals(validityEndDate) && DateUtil.compare(validityEndDate, now)) {
            return false;
        }
        return true;
    }

    private static ITenantService getBean() {
        return SpringBeanUtil.getBean(ITenantService.class);
    }
}
